﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Net;

namespace PartyCraftServer.Web.API
{
    public class API : WebController
    {
        /// <summary>
        /// String is auth token, DateTime is expiry time
        /// </summary>
        static Dictionary<string, DateTime> AuthTokens = new Dictionary<string, DateTime>();

        private static bool ValidateAuthToken(string token)
        {
            if (!AuthTokens.ContainsKey(token))
                return false;
            if (AuthTokens[token] < DateTime.UtcNow)
            {
                AuthTokens.Remove(token);
                return false;
            }
            return true;
        }

        private static DateTime ConvertFromUnixTimestamp(double timestamp)
        {
            DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return origin.AddSeconds(timestamp);
        }


        private static double ConvertToUnixTimestamp(DateTime date)
        {
            DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            TimeSpan diff = date - origin;
            return Math.Floor(diff.TotalSeconds);
        }

        const string MinecraftAuthUrl = "http://login.minecraft.net?user={0}&password={1}&version=12";
        public void GetToken(string UserName, string Password)
        {
            if (PartyCraft.Settings.ContainsKey("player." + UserName + ".op")
                && PartyCraft.Settings.GetBoolean("player." + UserName + ".op"))
            {
                // Authenticate with minecraft.net
                WebClient c = new WebClient();
                string s = c.DownloadString(string.Format(MinecraftAuthUrl, UserName, Password));
                if (s == "Bad login.")
                {
                    WriteResponse("Bad login.");
                    return;
                }
                string[] parts = s.Split(':');
                DateTime expiry = DateTime.UtcNow.AddDays(1);
                long token = long.Parse(parts[3]);
                if (token < 0)
                    token = -token;
                XDocument d = new XDocument();
                d.Add(new XElement("api"));
                d.Root.Add(new XElement("token", token));
                d.Root.Add(new XElement("expiry", ConvertToUnixTimestamp(expiry)));
                WriteXml(d);
                AuthTokens.Add(token.ToString(), expiry);
            }
            else
            {
                // Failed to authenticate
                WriteResponse("Bad login.");
            }
        }

        public void SendChat(string message)
        {
            if (!PartyCraft.WebService.LoggedInUsers.ContainsKey(Context.Request.RemoteEndPoint.Address.ToString()))
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Access denied.");
                return;
            }
            PartyCraft.Server.SendChat(message);
            PartyCraft.ChatLog.Add(new ChatLog(DateTime.Now, message));
        }

        public void SendChat(string Token, string Message)
        {
            if (!ValidateAuthToken(Token))
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Invalid authentication token.");
                return;
            }
            PartyCraft.Server.SendChat(Message);
            PartyCraft.ChatLog.Add(new ChatLog(DateTime.Now, Message));
        }

        public void UpdateChat()
        {
            if (!PartyCraft.WebService.LoggedInUsers.ContainsKey(Context.Request.RemoteEndPoint.Address.ToString()))
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Access denied.");
                return;
            }
            string html = "";
            foreach (string message in PartyCraft.GetLastFifteenMessages())
            {
                var text = message;
                text = WebService.ColorCodeHtml(text);
                html += text + "<br />";
            }
            Context.Response.ContentType = "text/plain";
            WriteResponse(html);
        }

        public void GetChat(string Token, long Time)
        {
            if (!ValidateAuthToken(Token))
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Invalid authentication token.");
                return;
            }
            DateTime time = ConvertFromUnixTimestamp(Time);
            var chatLog = PartyCraft.ChatLog.Where(c => c.Time.ToUniversalTime() > time);
            string result = "";
            foreach (var chat in chatLog)
                result += chat.Message + "\n";
            WriteResponse(result);
            Context.Response.ContentType = "text/plain";
        }

        public void KickPlayer(string Token, string Player, string Reason)
        {
            if (!ValidateAuthToken(Token))
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Invalid authentication token.");
                return;
            }
            if (PartyCraft.Server.GetClient(Player) == null)
            {
                WriteResponse("There is no player by that name online.");
                return;
            }
            PartyCraft.Server.KickPlayer(Player, Reason);
        }

        public void KickPlayer(string name, string reason)
        {
            if (!PartyCraft.WebService.LoggedInUsers.ContainsKey(Context.Request.RemoteEndPoint.Address.ToString()) &&
                PartyCraft.WebService.LoggedInUsers[Context.Request.RemoteEndPoint.Address.ToString()].Name == "TestUser")
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Access denied.");
                return;
            }
            PartyCraft.Server.KickPlayer(name, reason);
        }

        public void GetPlayers(string Token)
        {
            if (!ValidateAuthToken(Token))
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Invalid authentication token.");
                return;
            }
            XDocument d = new XDocument();
            d.Add(new XElement("api"));
            foreach (var p in PartyCraft.Server.GetLoggedInClients())
            {
                XElement e = new XElement("player");
                e.SetAttributeValue("name", p.PlayerEntity.Name);
                e.SetAttributeValue("coordinates", p.PlayerEntity.Location);
                e.SetAttributeValue("world", p.PlayerEntity.WorldIndex);
                d.Root.Add(e);
            }
            WriteXml(d);
        }

        public void GetSetting(string key)
        {
            if (!PartyCraft.WebService.LoggedInUsers.ContainsKey(Context.Request.RemoteEndPoint.Address.ToString()))
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Access denied.");
                return;
            }
            if (!PartyCraft.Settings.ContainsKey(key))
            {
                WriteResponse("Key not found.");
                return;
            }
            WriteResponse(PartyCraft.Settings[key]);
        }

        public void SetSetting(string key, string value)
        {
            if (!PartyCraft.WebService.LoggedInUsers.ContainsKey(Context.Request.RemoteEndPoint.Address.ToString()) ||
                PartyCraft.WebService.LoggedInUsers[Context.Request.RemoteEndPoint.Address.ToString()].Name == "TestUser")
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Access denied.");
                return;
            }
            PartyCraft.Settings[key] = value;
            WriteResponse(value);
        }

        public void Restart()
        {
            if (!PartyCraft.WebService.LoggedInUsers.ContainsKey(Context.Request.RemoteEndPoint.Address.ToString()) ||
                PartyCraft.WebService.LoggedInUsers[Context.Request.RemoteEndPoint.Address.ToString()].Name == "TestUser")
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Access denied.");
                return;
            }
            PartyCraft.AsyncAction = AsyncAction.RestartServer;
            PartyCraft.AsyncReset.Set();
            Context.Response.Close();
        }

        public void Setting(string token, string key)
        {
            if (!ValidateAuthToken(token))
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Invalid authentication token.");
                return;
            }
            if (!PartyCraft.Settings.ContainsKey(key))
            {
                WriteResponse("Key not found.");
                return;
            }
            WriteResponse(PartyCraft.Settings[key]);
        }

        public void Setting(string token, string key, string value)
        {
            if (!ValidateAuthToken(token))
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Invalid authentication token.");
                return;
            }
            PartyCraft.Settings[key] = value;
        }

        public void GetAnalytics(string key)
        {
            if (!PartyCraft.WebService.LoggedInUsers.ContainsKey(Context.Request.RemoteEndPoint.Address.ToString()) ||
                PartyCraft.WebService.LoggedInUsers[Context.Request.RemoteEndPoint.Address.ToString()].Name == "TestUser")
            {
                Context.Response.StatusCode = 401;
                WriteResponse("Access denied.");
                return;
            }
            switch (key)
            {
                
                default:
                    WriteResponse("Invalid parameter.");
                    break;
            }
        }

        public void Info()
        {
            XDocument d = new XDocument();
            d.Add(new XElement("partycraft"));
            d.Root.Add(new XElement("motd", PartyCraft.CurrentServer.MotD));
            d.Root.Add(new XElement("connected", PartyCraft.Server.ConnectedClients.Count));
            d.Root.Add(new XElement("max", PartyCraft.CurrentServer.MaxPlayers));
            d.Root.Add(new XElement("version", PartyCraft.Version.ToString()));
            d.Root.Add(new XElement("apitime", ConvertToUnixTimestamp(DateTime.UtcNow)));
            WriteXml(d);
        }

        public void Version()
        {
            WriteResponse(PartyCraft.Version.ToString());
        }
    }
}
